﻿#include "desk.h"
#include "log4z.h"
#include "msg_type.h"
#include "setup.pb.h"
#include "ui_main.h"
#include "mqtt_handler.h"
#include "json.hpp"
#include "share_data.h"
#include <QFile>
#include <QGroupBox>
#include <QTimer>
#include <QImage>
#include <QPushButton>
#include <QButtonGroup>
#include <QTextCodec>
#include <QInputDialog>
#include <QMessageBox>
#include <QCheckBox>
#include <QFileDialog>
#include <QCryptographicHash>
#include <QAction>
#include <QComboBox>
#include "mylabel.h"
using namespace msgType;
using namespace Ui;
static pb_io io;
/*
2024年4月25日16:17:39 版本1.3.2 新增升级功能
2024年5月5日21:43:00  版本1.3.3 
1.新增屏蔽功能
2.新增错误指示灯
3.新增半自动模式
4.新增恢复出厂设置
5.新增升级进度显示
6.新增卷线、卷绳速度设置
2024年7月4日10:09:383
1.新增恢复出厂设置程序的心跳
2024年9月1日15:18:21
1.新增测试模式
2024年9月14日12:41:21
1.新增全自动模式  V1.3.6
2025年3月19日08:59:04 
1.设置添加判空  V1.3.7
*/
desk::desk(QWidget* _parent):QMainWindow(_parent)
{
	up_version_ = "上位机编译时间:" + QString(__DATE__) + " " + __TIME__ + " 版本:V1.3.7";
	validator_ = new QDoubleValidator();
	lab_up = new QLabel(this);
	lab_down = new QLabel(this);
	lab_status = new QLabel(this);
	lab_ack = new QLabel(this);
	lab_status->setText("连接断开");
	ui.setupUi(this);
	err_label_[0] = ui.lab_err_bat;
	err_label_[1] = ui.lab_err_run;
	err_label_[2] = ui.lab_err_height;
	err_label_[3] = ui.lab_err_line;
	ui.statusBar->addWidget(lab_up);
	ui.statusBar->addWidget(new QLabel("|",this));
	ui.statusBar->addWidget(lab_down);
	ui.statusBar->addWidget(new QLabel("|", this));
	ui.statusBar->addWidget(lab_status);
	ui.statusBar->addWidget(new QLabel("|", this));
	ui.statusBar->addWidget(lab_ack);
	set_ui.setupUi(&set_win);
	mask_ui.setupUi(&mask_win);
	test_ui.setupUi(&test_win);
	menu_.addAction("添加动作");
	menu_.addAction("删除动作");
	menu_.addAction("清空");
	test_ui.line_run_speed->setText("400");
	test_ui.line_run_pos->setText("1.0");
	test_ui.line_delay_sec->setText("60");
	set1_lay_ = new QGridLayout(set_ui.tab_limit);
	set2_lay_ = new QGridLayout(set_ui.tab_arg);
	set3_lay_ = new QGridLayout(set_ui.tab_hard);
	Init();
	SubscribeData();
	process_dialog_.setWindowTitle("升级进度");
	process_dialog_.setVisible(false);
	process_dialog_.setMinimum(0);
	process_dialog_.setMaximum(100);
	process_dialog_.close();
	stamp_ = Setting::NowToMillseconds();
	QTimer* t = new QTimer;
	connect(t, &QTimer::timeout, [&]() {
#ifdef WIN32
		static int count = 0;
		if (Setting::NowToMillseconds() - stamp_ > 500)
		{
			link_ = false;
			lab_status->setText("连接断开");
			if (count++ % 2 == 0)
			{
				lab_status->setStyleSheet("background-color:red");
			}
			else
			{
				lab_status->setStyleSheet("background-color:grey");
			}
		}
		else
		{
			link_ = true;
			lab_status->setText("连接正常");
			lab_status->setStyleSheet("background-color:green");
		}
		if (Setting::NowToMillseconds() - factory_tick_ > 2000)
		{
			restore_run_ = false;
		}
#endif
		RefreshUiData();
		});
	t->start(200);
#ifdef WIN32
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/tick", [&](const char* _topic, const void* _pdata, int32_t)
		{
			stamp_ = Setting::NowToMillseconds();
			int32_t stamp_s = stamp_ / 1000;
			GET_MQTT_HANDLE["net"]->Publish("test/ack/tick", &stamp_s, 4);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/restore_tick", [&](const char* _topic, const void* _pdata, int32_t)
		{
			factory_tick_ = Setting::NowToMillseconds();
			restore_run_ = true;
		});
#endif
}
void desk::ImageInit()
{
	//设置故障灯
	
	//行走电机故障
	ui.lab_err_bat->setStyleSheet("border-image:url(icon/on.png)");
	ui.lab_err_bat->setText("");
	ui.lab_err_run->setStyleSheet("border-image:url(icon/on.png)");
	ui.lab_err_run->setText("");
	//提升电机故障
	ui.lab_err_height->setStyleSheet("border-image:url(icon/on.png)");
	ui.lab_err_height->setText("");
	//卷线电机故障
	ui.lab_err_line->setStyleSheet("border-image:url(icon/on.png)");
	ui.lab_err_line->setText("");

	//电源灯
	ui.lab_light->setText("");
	ui.lab_height_motor->setText("");
	ui.lab_rop->setText("");
	ui.lab_line->setText("");
	ui.lab_run_motor->setText("");
	ui.lab_shake->setText("");
	//故障灯移入 移除事件绑定
	connect(ui.lab_err_bat, &MyLabel::sig_Enter, [=]() {OnEnter(0); });
	connect(ui.lab_err_bat, &MyLabel::sig_Leave, [=]() {OnLeave(0); });

	connect(ui.lab_err_run, &MyLabel::sig_Enter, [=]() {OnEnter(1); });
	connect(ui.lab_err_run, &MyLabel::sig_Leave, [=]() {OnLeave(1); });

	connect(ui.lab_err_height, &MyLabel::sig_Enter, [=]() {OnEnter(2); });
	connect(ui.lab_err_height, &MyLabel::sig_Leave, [=]() {OnLeave(2); });

	connect(ui.lab_err_line, &MyLabel::sig_Enter, [=]() {OnEnter(3); });
	connect(ui.lab_err_line, &MyLabel::sig_Leave, [=]() {OnLeave(3); });


	lab_err_.setWordWrap(true);
	pop_win_.setWindowFlag(Qt::FramelessWindowHint);
	pop_win_.setStyleSheet("background-color:#E81123;");
	lab_err_.setStyleSheet("color:white;font-weight: 500;font-size: 14px;");
	auto widget = new QWidget;
	auto lay = new QVBoxLayout(widget);
	pop_win_.setCentralWidget(widget);
	lay->addWidget(&lab_err_);

}
void desk::LoadSetUpFile()
{
	//加载配置文件
	if (QFile::exists("config/set.json"))
	{
		QFile config("config/set.json");
		if (config.open(QIODevice::ReadOnly))
		{
			auto t = config.readAll().toStdString();
			try
			{
				nlohmann::json obj = nlohmann::json::parse(t);
				emit sig_DelWidget();
				set_widgets_.clear();
				advance_set_.clear();
				//加载配置文件
				for (auto item : obj.items())
				{
					for (auto sitem : item.value().items())
					{
						advance_set_.insert(std::make_pair(item.key()+ ":" + sitem.key(), sitem.value().get<std::string>()));
						emit sig_AddWidget((item.key() + ":" + sitem.key()).c_str(), sitem.value().get<std::string>().c_str());
					}
				}

				//设置上位机需要的参数
				if (advance_set_.find("soft_set:提升速度(rpm)") != advance_set_.end()) 
					height_motor_speed_ = std::stoi(advance_set_["soft_set:提升速度(rpm)"]);
				if (advance_set_.find("soft_set:行走速度(rpm)") != advance_set_.end())
					run_motor_speed_ = std::stoi(advance_set_["soft_set:行走速度(rpm)"]);
				set_ui.tabWidget->setTabEnabled(2,false);
			}
			catch (std::exception)
			{

			}
		}
	}
}
void desk::MenuInit()
{
	//添加设置界面菜单
	auto func_menu = new QMenu("文件");
	action_upgrade_ = new QAction("升级");
	action_restore_ = new QAction("恢复出厂设置");
	action_args_ = new QAction("参数设置");
	menuBar()->addMenu(func_menu);
	func_menu->addAction("故障屏蔽");
	connect(func_menu, SIGNAL(triggered(QAction*)), this, SLOT(slot_OnMenu(QAction*)));
	//管理员权限获取,管理员模式下,可以屏蔽异常,可以升级,可以恢复出厂设置
	connect(ui.ck_root, &QCheckBox::clicked, this, [=](bool _sta)
		{
			if (_sta)
			{
				ui.ck_root->setChecked(false);
				bool ok;
				QString text = QInputDialog::getText(this, "提示", "请输入密码", QLineEdit::Password, 0, &ok);
				if (ok && !text.isEmpty())
				{
					if (text == "123456")
					{
						ui.ck_root->setChecked(true);
						func_menu->addAction(action_upgrade_);
						func_menu->addAction(action_restore_);
						func_menu->addAction(action_args_);
					}
					else
					{
						QMessageBox::warning(nullptr, "警告", "密码错误");
					}

				}
				else
				{
					QMessageBox::warning(nullptr, "警告", "密码错误");
				}
			}
			else
			{
				func_menu->removeAction(action_restore_);
				func_menu->removeAction(action_upgrade_);
				func_menu->removeAction(action_args_);
				set_win.setVisible(false);
				mask_win.setVisible(false);
			}
		});
}
void desk::Init()
{
#ifdef WIN32
	connect(this, SIGNAL(sig_AddWidget(QString, QString)), this, SLOT(slot_AddWidget(QString, QString)));
	connect(this, SIGNAL(sig_DelWidget()), this, SLOT(slot_DelWidget()));
	connect(this, SIGNAL(sig_Alert(QString)), this, SLOT(slot_Alert(QString)));
	connect(this, SIGNAL(sig_Alert(QString,int)), this, SLOT(slot_Alert(QString,int)));
	connect(this, SIGNAL(sig_Ack(QString)), this, SLOT(slot_Ack(QString)));
#endif
	MenuInit();
	LoadSetUpFile();
	ImageInit();
#pragma region 添加测试动作种类
	test_ui.combo_type->addItem("提升机构");
	test_ui.combo_type->addItem("行走机构");
	test_ui.combo_type->addItem("延时操作");
	test_ui.combo_type->setCurrentText("提升机构");
	test_ui.line_delay_sec->setEnabled(false);
#pragma endregion

#ifdef WIN32
#endif
#pragma region  按钮绑定
	//上下左右、停止按钮绑定
	connect(ui.btn_up, &QCheckBox::clicked, [=](bool _ck) {
		if (_ck)
		{
			ui.btn_down->setChecked(false);
			pb_run_ctrl cmd;
			cmd.set_name("height");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			cmd.set_speed_percent(-height_motor_speed_);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		}
		else
		{
			pb_run_ctrl cmd;
			cmd.set_name("height");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		}
		});
	connect(ui.btn_down, &QCheckBox::clicked, [=](bool _ck) {
		if (_ck)
		{
			ui.btn_up->setChecked(false);
			pb_run_ctrl cmd;
			cmd.set_name("height");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			cmd.set_speed_percent(height_motor_speed_);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		}
		else
		{
			pb_run_ctrl cmd;
			cmd.set_name("height");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		}
		});
	connect(ui.btn_left, &QCheckBox::clicked, [=](bool _ck) {
		if (_ck)
		{
			ui.btn_right->setChecked(false);
			pb_run_ctrl cmd;
			cmd.set_name("run");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			cmd.set_speed_percent(-run_motor_speed_);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		}
		else
		{
			pb_run_ctrl cmd;
			cmd.set_name("run");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		}
		});
	connect(ui.btn_right, &QCheckBox::clicked, [=](bool _ck) {
		if (_ck)
		{
			ui.btn_left->setChecked(false);
			pb_run_ctrl cmd;
			cmd.set_name("run");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			cmd.set_speed_percent(run_motor_speed_);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		}
		else
		{
			pb_run_ctrl cmd;
			cmd.set_name("run");
			cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
			std::string data;
			cmd.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		}
		});
	
	connect(ui.btn_height_on, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_height_off, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	
	connect(ui.btn_run_on, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_run_off, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	connect(ui.btn_rop_on, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_rop_off, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	connect(ui.btn_line_on, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_line_off, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	connect(ui.btn_light_on, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_light_off, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	connect(ui.btn_shake_on, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_shake_off, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	connect(ui.btn_h_zero, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_v_zero, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	connect(ui.btn_stop, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_stop_2, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	connect(ui.btn_rop_sure, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_line_sure, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_line_sure, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	//停止
	connect(ui.btn_stop_line, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_stop_rop, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_stop_sync, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(set_ui.btn_set_hardware, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	
	//半自动模式
	connect(ui.btn_shake_time, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_mode2_shake, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_mode3_shake, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	//自动模式
	connect(ui.btn_start_auto,SIGNAL(clicked()),this,SLOT(slot_OnButton()));
	connect(ui.btn_stop_auto, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_suspend_auto, SIGNAL(clicked()), this, SLOT(slot_OnButton()));
	connect(ui.btn_resume_auto, SIGNAL(clicked()), this, SLOT(slot_OnButton()));

	//测试模式
	connect(ui.btn_test_import,SIGNAL(clicked()),this,SLOT(slot_OnButton()));
	connect(ui.btn_test_export,SIGNAL(clicked()),this,SLOT(slot_OnButton()));
	connect(ui.btn_test_resume,SIGNAL(clicked()),this,SLOT(slot_OnButton()));
	connect(ui.btn_test_start,SIGNAL(clicked()),this,SLOT(slot_OnButton()));
	connect(ui.btn_test_stop,SIGNAL(clicked()),this,SLOT(slot_OnButton()));
	connect(ui.btn_test_suspend,SIGNAL(clicked()),this,SLOT(slot_OnButton()));


	connect(test_ui.combo_type, &QComboBox::currentTextChanged, [&](const QString&) {
		if (test_ui.combo_type->currentIndex() == 2)
		{
			test_ui.line_run_pos->setEnabled(false);
			test_ui.line_run_speed->setEnabled(false);
			test_ui.line_delay_sec->setEnabled(true);
		}
		else
		{
			test_ui.line_delay_sec->setEnabled(false);
			test_ui.line_run_pos->setEnabled(true);
			test_ui.line_run_speed->setEnabled(true);

		}
		});
#pragma region 测试模式的列表右键菜单
	ui.list_test->setProperty("contextMenuPolicy", Qt::CustomContextMenu);
	connect(ui.list_test->model(), &QAbstractItemModel::rowsMoved, this, [=](const QModelIndex& parent, int start, int end, const QModelIndex& destination, int row)
		{
			//ui.list_test->move(start, end);
		});
	connect(&menu_, &QMenu::triggered, [&](QAction* _action) {
		if (_action->text() == "添加动作")
		{
			test_win.show();
		}
		else if (_action->text() == "删除动作")
		{
			auto pitem = ui.list_test->item(ui.list_test->currentIndex().row());
			if (pitem)
			{
				ui.list_test->removeItemWidget(pitem);
				delete pitem;
			}
		}
		else if (_action->text() == "清空")
		{
			ui.list_test->clear();
		}
		/*else if (_action->text() == "修改动作")
		{
			QString cur_line = ui.list_test->itemAt(QCursor::pos())->text();

		}*/
		});
	connect(ui.list_test, &QListWidget::customContextMenuRequested, [=](const QPoint& pos) {
		menu_.exec(QCursor::pos());
		});
//test form的按钮绑定
	connect(test_ui.btn_test_true, &QPushButton::clicked, [&]() {
		//添加一行数据
		QString line;
		if (test_ui.combo_type->currentText() == "延时操作")
		{
			if (test_ui.line_delay_sec->text() == "")
			{
				QMessageBox::warning(nullptr,"warn", "时间为空");
				return;
			}
			line = "类型:" + test_ui.combo_type->currentText() + "&" + "时间:" + test_ui.line_delay_sec->text()+"&";
			if (test_ui.checkBox->isChecked())
			{
				line += "震动:开";
			}
			else
			{
				line += "震动:关";
			}
		}
		else
		{
			if (test_ui.line_run_pos->text() == "" || test_ui.line_run_speed->text() == "")
			{
				QMessageBox::warning(nullptr, "warn", "速度或者距离为空");
				return;
			}
			line = "类型:" + test_ui.combo_type->currentText() + "&" + "速度:" + test_ui.line_run_speed->text() + "&" +
				"距离:" + test_ui.line_run_pos->text()+"&";
			if (test_ui.checkBox->isChecked())
			{
				line += "震动:开";
			}
			else
			{
				line += "震动:关";
			}
		}
		int current_row = ui.list_test->indexAt(QCursor::pos()).row();
		if (current_row == -1)
		{
			ui.list_test->insertItem( ui.list_test->count(),line);
		}
		else {
			ui.list_test->insertItem(current_row, line);
		}
		ui.list_test->clearSelection();
		test_ui.line_delay_sec->setText("");
		test_ui.line_run_pos->setText("1.0");
		test_ui.line_run_speed->setText("400");
		test_win.setVisible(false);
		});
#pragma endregion


#pragma region 屏蔽按钮绑定
	connect(mask_ui.ck_mask_left_limit, &QCheckBox::clicked, [=](bool _ck) {
		std::string val = std::to_string(!_ck);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/param/soft_limit:前进限位", val.c_str(), val.length());
		//更新本地参数
		GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);
		if (_ck)
		{
			mask_run_.set_mask_pos = back_.position();
		}
		});
	connect(mask_ui.ck_mask_right_limit, &QCheckBox::clicked, [=](bool _ck) {
		std::string val = std::to_string(!_ck);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/param/soft_limit:后退限位", val.c_str(), val.length());
		//更新本地参数
		GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);
		if (_ck)
		{
			mask_run_.set_mask_pos = back_.position();
		}
		});
	connect(mask_ui.ck_mask_up_limit, &QCheckBox::clicked, [=](bool _ck) {
		std::string val = std::to_string(!_ck);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/param/soft_limit:提升限位功能", val.c_str(), val.length());
		//更新本地参数
		GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);

		});
	connect(mask_ui.ck_mask_min_down, &QCheckBox::clicked, [=](bool _ck) {
		std::string val = std::to_string(!_ck);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/param/soft_limit:下降拉力屏蔽", val.c_str(), val.length());
		//更新本地参数
		GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);

		});
	connect(mask_ui.ck_mask_max_up, &QCheckBox::clicked, [=](bool _ck) {
		std::string val = std::to_string(!_ck);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/param/soft_limit:提升拉力屏蔽", val.c_str(), val.length());
		//更新本地参数
		GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);

		});
#pragma endregion

#pragma endregion
#pragma region 输入框输入限制
	ui.edit_height_pos->setValidator(validator_);
	ui.edit_height_speed->setValidator(new QIntValidator);
	ui.edit_line_motor->setValidator(new QIntValidator);
	ui.edit_rop_motor->setValidator(validator_);
	ui.edit_run_pos->setValidator(validator_);
	ui.edit_run_speed->setValidator(new QIntValidator);
	ui.edit_shake_time->setValidator(new QIntValidator);
	ui.edit_sync->setValidator(validator_);
	ui.input_a->setValidator(new QIntValidator);
	ui.input_b->setValidator(validator_);
	ui.input_c->setValidator(validator_);
	ui.input_d->setValidator(new QIntValidator);
	ui.input_e->setValidator(validator_);
	ui.input_f->setValidator(validator_);
	ui.input_times->setValidator(new QIntValidator);
#pragma endregion

}
void desk::slot_Alert(QString _msg)
{
	if (_msg == "ok")
	{
		QMessageBox::warning(this, "提示", "升级成功");
		process_dialog_flag_ = false;
		process_dialog_.setVisible(false);
	}
	else
	{
		QMessageBox::warning(this, "提示", "升级失败");
		process_dialog_flag_ = false;
		process_dialog_.setVisible(false);
	}
}
void desk::slot_Alert(QString _type, int _typeNum)
{
	if (_type == "request" && _typeNum == 0)
	{
		static bool alert_flag = false;
		if (alert_flag) return;
		alert_flag = true;
		auto ret = QMessageBox::question(this, "提示", "触发垂直限位,是否设置垂直零位",
			QMessageBox::Yes | QMessageBox::No);
		if (ret == QMessageBox::Yes)
		{
			std::string data;
			pb_run_ctrl cmd_run;
			cmd_run.set_name("height");
			cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_ZERO);
			cmd_run.SerializeToString(&data);
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		}
		alert_flag = false;
	}
	if (_type == "process")
	{
		process_dialog_.setValue(_typeNum);
		if (!process_dialog_flag_)
		{
			LOGFMTD("update process=%d", _typeNum);
			process_dialog_flag_ = true;
			process_dialog_.setLabelText("升级中。。。");
			process_dialog_.setWindowTitle("升级进度");
			process_dialog_.update();
			process_dialog_.show();
		}
	}
	if (_type == "restore")
	{
		QMessageBox::warning(this, "提示", "恢复出厂设置成功");
	}
}
void desk::slot_Ack(QString _str)
{
	lab_ack->setText(_str);
	QTimer::singleShot(2000, [&]() {
		lab_ack->setText("");
		});
}
void desk::OnEnter(int _index)
{
	QString err_txt;
	std::sort(err_show[_index].begin(), err_show[_index].end());
	for (auto v : err_show[_index])
		err_txt += (v + "\n");
	lab_err_.setText(err_txt);
	pop_win_.setVisible(false);
	//pop_win_.setFixedSize(max_width * lab_err_.fontMetrics().height(),(err_store_[group].size()+1) * (lab_err_.fontMetrics().height()+4)+30);
	pop_win_.move(QCursor::pos().x() + 10, QCursor::pos().y());
	if (err_show[_index].size() > 0)
		pop_win_.show();
}
void desk::OnLeave(int _index)
{
	pop_win_.setVisible(false);
}
void desk::RefreshUiData()
{
	char buf[128] = { 0 };
#pragma region 设置电源灯的颜色

	if (bms_.height_motor()) ui.lab_height_motor->setStyleSheet("border-image:url(icon/on.png)");
	else  ui.lab_height_motor->setStyleSheet("border-image:url(icon/off.png)");
	
	if (bms_.run_motor()) ui.lab_run_motor->setStyleSheet("border-image:url(icon/on.png)");
	else  ui.lab_run_motor->setStyleSheet("border-image:url(icon/off.png)");

	if (bms_.line_motor()) ui.lab_line->setStyleSheet("border-image:url(icon/on.png)");
	else  ui.lab_line->setStyleSheet("border-image:url(icon/off.png)");

	if (bms_.rop_motor()) ui.lab_rop->setStyleSheet("border-image:url(icon/on.png)");
	else  ui.lab_rop->setStyleSheet("border-image:url(icon/off.png)");

	if (bms_.lighta()) ui.lab_light->setStyleSheet("border-image:url(icon/on.png)");
	else  ui.lab_light->setStyleSheet("border-image:url(icon/off.png)");

	if (bms_.shakea_motor()) ui.lab_shake->setStyleSheet("border-image:url(icon/on.png)");
	else  ui.lab_shake->setStyleSheet("border-image:url(icon/off.png)");
#pragma endregion
#pragma region 行走电机部分的显示
	buf[0] = 0;
	sprintf(buf, "编码器水平位置:%.2f m", back_.position());
	ui.lab_h_pos->setText(buf);
	buf[0] = 0;
	sprintf(buf, "行走电机A位置: %.2f m", runa_.position());
	ui.lab_a_pos->setText(buf);
	buf[0] = 0;
	sprintf(buf, "行走电机B位置: %.2f m", runb_.position());
	ui.lab_b_pos->setText(buf);
	if (runa_.sta() == 1)
		ui.lab_run_arrive->setText("行走位置到达");
	else if (runa_.sta() == 2)
		ui.lab_run_arrive->setText("运行中");
	else if (runa_.sta() == 0)
		ui.lab_run_arrive->setText("当前为速度模式");

#pragma endregion
#pragma region 行走电机屏蔽自动恢复
	if (mask_ui.ck_mask_left_limit->isChecked() || mask_ui.ck_mask_right_limit->isChecked())//比较位置
	{
		float auto_clear = 4.0;
		if (advance_set_.find("soft_limit:行走限位自动取消屏蔽距离(m)") != advance_set_.end())
			auto_clear = std::stof(advance_set_["soft_limit:行走限位自动取消屏蔽距离(m)"]);
		if (fabs(back_.position() - mask_run_.set_mask_pos) > auto_clear)
		{
			mask_ui.ck_mask_left_limit->setChecked(false);
			mask_ui.ck_mask_right_limit->setChecked(false);
			std::string val = "1";//发送屏蔽
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/param/soft_limit:前进限位", val.c_str(), val.length());
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/param/soft_limit:后退限位", val.c_str(), val.length());
			LOGFMTD("Mask auto clear");
		}
	}
#pragma endregion

#pragma region 提升电机部分的显示
	buf[0] = 0;
	sprintf(buf, "垂直位置:%.2f m", height_.position());
	ui.lab_v_pos->setText(buf);
	if (height_.sta() == 1)
		ui.lab_height_arrive->setText("提升位置到达");
	else if(height_.sta() == 2)
		ui.lab_height_arrive->setText("运行中");
	else if(height_.sta() == 0)
		ui.lab_height_arrive->setText("当前为速度模式");
#pragma endregion

#pragma region 异常显示
	//行走电机异常
	auto err_runa = runa_.mutable_errs();
	//err_runa->Clear();
	//err_runa->Add("触发左限位");
	//err_runa->Add("触发右限位");
	auto err_runb = runb_.mutable_errs();
	if (err_runa->size() || err_runb->size())
	{
		err_show[1].clear();
		err_link_[1] = 1;
		for (int i = 0; i < err_runa->size(); i++){
			if(err_runa->Get(i).find("限位") != std::string::npos)
				err_show[1].push_back(err_runa->Get(i).c_str());
			else
				err_show[1].push_back(("左行走电机"+err_runa->Get(i)).c_str());
		}
		for (int i = 0; i < err_runb->size(); i++) {

			if (err_runa->Get(i).find("限位") != std::string::npos)
				err_show[1].push_back(err_runb->Get(i).c_str());
			else
				err_show[1].push_back(("右行走电机" + err_runb->Get(i)).c_str());
		}
	}
	else
	{
		err_show[1].clear();
		err_link_[1] = 0;
	}
	//提升电机异常
	auto err_height = height_.mutable_errs();
	//err_height->Clear();
	//err_height->Add("触发上限位");
	if (err_height->size())
	{
		err_show[2].clear();
		err_link_[2] = 1;
		for (int i = 0; i < err_height->size(); i++) err_show[2].push_back(err_height->Get(i).c_str());
	}
	else
	{
		err_show[2].clear();
		err_link_[2] = 0;
	}

	//卷线卷绳电机
	auto err_rop_ = rop_motor_.mutable_errs();
	auto err_line_ = line_motor_.mutable_errs();
	//err_height->Clear();
	//err_height->Add("触发上限位");
	if (err_rop_->size() || err_line_->size())
	{
		err_show[3].clear();
		err_link_[3] = 1;
		for (int i = 0; i < err_rop_->size(); i++) 
			err_show[3].push_back(("卷绳电机"+err_rop_->Get(i)).c_str());
		for (int i = 0; i < err_line_->size(); i++)
			err_show[3].push_back(("卷线电机" + err_line_->Get(i)).c_str());
	}
	else
	{
		err_show[3].clear();
		err_link_[3] = 0;
	}
	


	//异常闪烁代码
	static int link_count = 0;
	for (int i = 0; i < 4; i++)
	{
		if (err_link_[i] == 1)
		{
			if(link_count % 2 == 0)
				err_label_[i]->setStyleSheet("border-image:url(icon/red.png)");
			else
				err_label_[i]->setStyleSheet("border-image:url(icon/off.png)");
		}
		else
		{
			err_label_[i]->setStyleSheet("border-image:url(icon/on.png)");
		}
	}
	link_count++;
#pragma endregion

#pragma region 电池信息
	//取第一路电池数据进行显示
	float v = 0;
	float p = 0;
	int cap = 0;
	int count = 0;
	for (int i = 1; i <= 6; i++)
	{
		auto bat = GET_SHARE_DATA(pb_bat, std::to_string(i));
		if (bat->votage() > 1.0)
		{
			count++;
			v += bat->votage();
			cap += bat->cap_percent();
			p += bat->power();
		}
	}
	if (count > 0)
	{
		char buf[128] = { 0 };
		sprintf(buf, "平均电压:%.2fV", (float)(v / count));
		ui.lab_votage->setText(buf);
		buf[0] = { 0 };
		sprintf(buf, "总功率:%.2fW", p);
		ui.lab_power->setText(buf);
		buf[0] = { 0 };
		sprintf(buf, "平均电量:%d%%", cap/count);
		ui.lab_cap->setText(buf);
	}
	//设置电池信息
	auto bat1 = GET_SHARE_DATA(pb_bat,"1");
	auto bat2 = GET_SHARE_DATA(pb_bat, "2");
	auto bat3 = GET_SHARE_DATA(pb_bat, "3");
	auto bat4 = GET_SHARE_DATA(pb_bat, "4");
	auto bat5 = GET_SHARE_DATA(pb_bat, "5");
	auto bat6 = GET_SHARE_DATA(pb_bat, "6");
	sprintf(buf,"电池1:\n电压:%.2fV\n电流:%.2f\n功率:%.1f\n电量:%d%%",bat1->votage(),bat1->current(),bat1->power(),bat1->cap_percent());
	set_ui.lab_bat1->setText(buf);
	buf[0] = 0;
	sprintf(buf,"电池2:\n电压:%.2fV\n电流:%.2f\n功率:%.1f\n电量:%d%%",bat2->votage(),bat2->current(),bat2->power(),bat2->cap_percent());
	set_ui.lab_bat2->setText(buf);
	buf[0] = 0;
	sprintf(buf,"电池3:\n电压:%.2fV\n电流:%.2f\n功率:%.1f\n电量:%d%%",bat3->votage(),bat3->current(),bat3->power(),bat3->cap_percent());
	set_ui.lab_bat3->setText(buf);
	buf[0] = 0;
	sprintf(buf,"电池4:\n电压:%.2fV\n电流:%.2f\n功率:%.1f\n电量:%d%%",bat4->votage(),bat4->current(),bat4->power(),bat4->cap_percent());
	set_ui.lab_bat4->setText(buf);
	buf[0] = 0;
	sprintf(buf,"电池5:\n电压:%.2fV\n电流:%.2f\n功率:%.1f\n电量:%d%%",bat5->votage(),bat5->current(),bat5->power(),bat5->cap_percent());
	set_ui.lab_bat5->setText(buf);
	buf[0] = 0;
	sprintf(buf,"电池6:\n电压:%.2fV\n电流:%.2f\n功率:%.1f\n电量:%d%%", bat6->votage(), bat6->current(), bat6->power(), bat6->cap_percent());
	set_ui.lab_bat6->setText(buf);
	buf[0] = 0;

#pragma endregion

#pragma region 拉力，震动功率，提升功率，料位
	auto adc0 = GET_SHARE_DATA(pb_dev_work_sta, "adc_0");
	buf[0] = 0;
	//4-20mA   0.6V-3V    0kg-1500kg
	float force = (adc0->votage() - 0.6) / 2.4 * 1500;
	if (force <= 0.1) force = 0.1;
	
	sprintf(buf,"拉力:%.1f kg",force);
	ui.lab_force->setText(buf);

	auto adc4 = GET_SHARE_DATA(pb_dev_work_sta, "adc_4");
	buf[0] = 0;
	float series = 20 / (4.5 - 0.5);
	float shakea_p = (adc4->votage() * 2 - 0.5) * series;
	if (shakea_p < 0) shakea_p = 0;
	sprintf(buf, "卷线功率A:%.1f W", (int)shakea_p*24.0);
	ui.lab_shakea_power->setText(buf);

	auto adc5 = GET_SHARE_DATA(pb_dev_work_sta, "adc_5");
	buf[0] = 0;
	float shakeb_p = (adc5->votage() * 2 - 0.5) * series;
	if (shakeb_p < 0) shakeb_p = 0;
	sprintf(buf, "卷绳功率B:%.1f W", (int)shakeb_p* 24.0);
	ui.lab_shakeb_power->setText(buf);

	buf[0] = 0;
	sprintf(buf, "提升功率:%d W", (int)(height_.votage()*height_.current()));
	ui.lab_height_power->setText(buf);
	//料位1，料位2
	auto adc1 = GET_SHARE_DATA(pb_dev_work_sta, "adc_1");
	buf[0] = 0;
	float adc1_val = 0;
	if (adc1->votage() <= 0.6) adc1_val = 0.6;
	else adc1_val = adc1->votage();
	float dis_series = 1.0 / 2.4;
	sprintf(buf,"料位1:%.2f m",(adc1_val-0.6)*dis_series);
	ui.lab1_v->setText(buf);
	auto adc2 = GET_SHARE_DATA(pb_dev_work_sta, "adc_2");
	float adc2_val = 0;
	if (adc2->votage() <= 0.6) adc2_val = 0.6;
	else adc2_val = adc2->votage();
	buf[0] = 0;
	sprintf(buf, "料位2:%.2f m", (adc2_val - 0.6) * dis_series);
	ui.lab2_v->setText(buf);

#pragma endregion

#pragma region 程序版本信息
	lab_up->setText(up_version_);
	lab_down->setText(down_version_);
#pragma endregion

#pragma region 测试模式上报信息显示
	std::string state_show;//当前状态:当前循环次数:当前执行动作
	if (state_.mode() == 4)
		state_show = "当前状态:测试模式";
	else if (state_.mode() == 3)
		state_show = "当前状态:自动模式";
	else 
		state_show = "当前状态:空闲模式";
	state_show += "	当前循环次数:" + std::to_string(state_.cycle_num());
	state_show += "	当前执行动作:" + std::to_string(state_.action_num());
	ui.lab_test_state->setText(state_show.c_str());
#pragma endregion


#pragma region 自动模式的上报信息显示
	std::string state_show_auto;
	if (state_.mode() == 4)
		state_show_auto = "当前状态:测试模式";
	else if (state_.mode() == 3)
		state_show_auto = "当前状态:自动模式";
	else
		state_show_auto = "当前状态:空闲模式";
	state_show_auto += " 当前动作:" + state_.note();
	if (state_.rest_time() > 1)
		state_show_auto += " 剩余震动时间:" + std::to_string(state_.rest_time()) + "s";
	if(state_.note() != "初始状态")
		state_show_auto += " 当前点数:" + std::to_string(state_.cycle_num());
	ui.lab_cur_state->setText(state_show_auto.c_str());
#pragma endregion

}
void desk::SubscribeData()
{
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/version", [&](const char* _topic, const void* _pdata, int32_t _len)
		{
			std::string s((char*)_pdata,_len);
			down_version_ = s.c_str();
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/ack/update", [&](const char* _topic, const void* _pdata, int32_t _len)
		{
			std::string s((char*)_pdata, _len);
			emit sig_Alert(s.c_str());
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/ack/restore_factory", [&](const char* _topic, const void* _pdata, int32_t _len)
		{
			emit sig_Alert("restore",1);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/ack/update_process", [&](const char* _topic, const void* _pdata, int32_t _len)
		{
			int process = *(int*)_pdata;
			emit sig_Alert("process",process);
		});
	GET_MQTT_HANDLE["net"]->SubTopicWildcard("test/data/pb_bat/+",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			using namespace msgType;
			std::string s(_topic);
			std::smatch result;
			if (regex_match(s, result, re_))
			{
				auto bat_ptr = GET_SHARE_DATA(pb_bat, result.str(1));
				bat_ptr->ParseFromArray(_pdata, _len);
			}
		});
	GET_MQTT_HANDLE["net"]->SubTopicWildcard("test/data/pb_io/+",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			using namespace msgType;
			std::string s(_topic);
			std::smatch result;
			if (regex_match(s, result, io_re_))
			{
				if (result.str(1) == advance_set_["hardware:up_limit"]) up_limit_io_.ParseFromArray(_pdata, _len);
				else if (result.str(1) == advance_set_["hardware:left_limit"]) left_limit_io_.ParseFromArray(_pdata, _len);
				else if (result.str(1) == advance_set_["hardware:right_limit"]) right_limit_io_.ParseFromArray(_pdata, _len);
			}
		});
	GET_MQTT_HANDLE["net"]->SubTopicWildcard("test/data/pb_dev_work_sta/+",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			using namespace msgType;
			std::string s(_topic);
			std::smatch result;
			if (regex_match(s, result, adc_re_))
			{

				auto adc_ptr = GET_SHARE_DATA(pb_dev_work_sta, result.str(1));
				adc_ptr->ParseFromArray(_pdata, _len);
			}
		});

	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_run_bms",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			bms_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_encoder/back",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			back_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_encoder/rop",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			rop_motor_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_encoder/line",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			line_motor_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_encoder/run",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			runa_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_encoder/runb",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			runb_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_encoder/height",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			height_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/notify/vertical/clear",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			sig_Alert("request",0);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/data/pb_dev_state",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			state_.ParseFromArray(_pdata, _len);
		});
	GET_MQTT_HANDLE["net"]->SubTopic("test/ack/pb_run_test_item",
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			pb_run_test_item item;
			item.ParseFromArray(_pdata, _len);
			std::string sta = "成功";
			std::string ack_str;
			if (item.sta() == 2)
			{
				sta = "失败";
			}
			if (item.type() == typeTestType::TEST_START) ack_str == "测试开始";
			else if (item.type() == typeTestType::TEST_STOP) ack_str == "测试停止";
			else if (item.type() == typeTestType::TEST_RESUME) ack_str == "测试恢复";
			else if (item.type() == typeTestType::TEST_SUSPEND) ack_str == "测试挂起";
			ack_str += sta;
			ack_str += item.ret();
			emit sig_Ack(ack_str.c_str());
		});
#ifdef WIN32
	GET_MQTT_HANDLE["net"]->SubTopic("test/ack/pb_run_setting", 
		[&](const char* _topic, const void* _pdata, int32_t _len)
		{
			FILE* fp = fopen("config/set.json","wb+");
			if (fp)
			{
				fwrite(_pdata,_len,1,fp);
				fflush(fp);
				fclose(fp);
			}
			std::string s((char*)_pdata, _len);
			try
			{
				
				nlohmann::json obj = nlohmann::json::parse(s);
				LoadSetUpFile();
			}
			catch (std::exception )
			{
				
			}			
		});
	GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);

#endif
}
//发送测试使用的任务
void desk::MakeMission(msgType::pb_run_test_item& _item)
{
	for (int i = 0; i < ui.list_test->count(); i++)
	{
		auto s = ui.list_test->item(i)->text();
		auto ret = s.split("&");
		if (ret.size() == 3)
		{
			auto track = _item.add_unit();
			track->set_type(typeTestType::TEST_DELAY);
			int secs = std::stoi(ret[1].remove("时间:").toStdString());
			track->set_delay_sec(secs);
			if (ret[2].indexOf("开") != -1)
			{
				track->set_shake_enable(true);
			}
		}
		else if (ret.size() == 4)
		{
			auto track = _item.add_unit();
			if (ret[0].indexOf("提升") != -1) track->set_type(typeTestType::TEST_HEIGHT);
			else track->set_type(typeTestType::TEST_RUN);
			int speed = std::stoi(ret[1].remove("速度:").toStdString());
			float pos = std::stof(ret[2].remove("距离:").toStdString());
			track->set_speed(speed);
			track->set_position(pos);
			if (ret[3].indexOf("开") != -1)
			{
				track->set_shake_enable(true);
			}
		}
	}
}
void desk::slot_OnPressButton()
{
	LOGFMTD("%s-pressed", ((QPushButton*)sender())->objectName().toStdString().c_str());
	std::string name = ((QPushButton*)sender())->objectName().toStdString();
	if (name == "btn_left")
	{
		pb_run_ctrl cmd;
		cmd.set_name("run");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd.set_speed_percent(-run_motor_speed_);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/run", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_right")
	{
		pb_run_ctrl cmd;
		cmd.set_name("run");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd.set_speed_percent(run_motor_speed_);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/run", cmd.DebugString().c_str(), cmd.DebugString().length());

	}
	else if (name == "btn_up")
	{
		height_sta_ = 2;
		pb_run_ctrl cmd;
		cmd.set_name("height");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd.set_speed_percent(-height_motor_speed_);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/height", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_down")
	{
		height_sta_ = 3;
		pb_run_ctrl cmd;
		cmd.set_name("height");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd.set_speed_percent(height_motor_speed_);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/height", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
}
void desk::slot_OnReleaseButton()
{
	LOGFMTD("%s-released", ((QPushButton*)sender())->objectName().toStdString().c_str());
	std::string name = ((QPushButton*)sender())->objectName().toStdString();
	if (name == "btn_left")
	{
		pb_run_ctrl cmd;
		cmd.set_name("run");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/run", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_right")
	{
		pb_run_ctrl cmd;
		cmd.set_name("run");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/run", cmd.DebugString().c_str(), cmd.DebugString().length());

	}
	else if (name == "btn_up")
	{
		height_sta_ = 1;
		pb_run_ctrl cmd;
		cmd.set_name("height");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_STOP);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/height", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_down")
	{
		height_sta_ = 1;
		pb_run_ctrl cmd;
		cmd.set_name("height");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_STOP);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_ctrl/height", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
}
void desk::slot_OnMenu(QAction* _action)
{
	LOGFMTD("click menu %s",_action->text().toStdString().c_str());
	if (_action->text() == "升级")
	{
		if (update_flag_)
		{
			QMessageBox::warning(this, "警告", "正在升级中");
			return;
		}
		auto fileName = QFileDialog::getOpenFileName(this, "选择升级文件", ".", "*.tar.gz");
		QFile file(fileName);
		if (file.open(QIODevice::ReadOnly))
		{
			int total_len = file.size();
			uint8_t* pread = new uint8_t[total_len];
			auto t = file.readAll();
			QByteArray hashData = QCryptographicHash::hash(t, QCryptographicHash::Md5);
			//返回字节数组的十六进制编码，编码使用数字0-9和字母a-f
			QString md5 = hashData.toHex();
			int total_pack = total_len / pack_len_;
			if (total_len % pack_len_ > 0) total_pack += 1;
			memcpy(pread,t.toStdString().c_str(),t.toStdString().length());
			std::string name = fileName.toStdString();
			int pos = name.find_last_of("/");
			if (pos != std::string::npos)
			{
				name = name.substr(pos + 1);
				memcpy(mqtt_trans_.name, name.c_str(), name.length() + 1);
				mqtt_trans_.total_len = total_len;
				mqtt_trans_.total_pack = total_pack;
				mqtt_trans_.cur_pack = 0;
				memcpy(mqtt_trans_.md5,md5.toStdString().c_str(),md5.toStdString().length());
				uint8_t* tmp = new uint8_t[sizeof(mqtt_file_t) + pack_len_];
				std::thread update_process([=]() {
					for (int i = 0; i < mqtt_trans_.total_pack - 1; i++)
					{
						if (i == 0) mqtt_trans_.trans_flag = 1;
						else mqtt_trans_.trans_flag = 2;
						mqtt_trans_.len = pack_len_;
						memcpy(tmp, &mqtt_trans_, sizeof(mqtt_file_t));
						memcpy(tmp + sizeof(mqtt_file_t), pread + i * pack_len_, pack_len_);
						if (GET_MQTT_HANDLE["net"])
						{
							GET_MQTT_HANDLE["net"]->Publish("test/raw/update", tmp, pack_len_ +sizeof(mqtt_file_t), 2);
							trans_bytes_ += mqtt_trans_.len;
							emit sig_UpdateProcess(trans_bytes_, mqtt_trans_.total_len);
							FILE* tfile = fopen("test.bin", "wb");
							if (tfile)
							{
								fwrite(tmp, 1, sizeof(mqtt_file_t), tfile);
								fclose(tfile);
							}
						}
						mqtt_trans_.cur_pack++;
						Sleep(1);
					}
					//发送最后一包
					mqtt_trans_.trans_flag = 3;
					memcpy(tmp, &mqtt_trans_, sizeof(mqtt_file_t));
					memcpy(tmp + sizeof(mqtt_file_t), pread + mqtt_trans_.cur_pack * pack_len_, mqtt_trans_.total_len % pack_len_);
					mqtt_trans_.len = mqtt_trans_.total_len % pack_len_;
					if (GET_MQTT_HANDLE["net"])
					{
						GET_MQTT_HANDLE["net"]->Publish("test/raw/update", tmp, mqtt_trans_.len + sizeof(mqtt_file_t), 2);
						trans_bytes_ += mqtt_trans_.len;
						emit sig_UpdateProcess(trans_bytes_, mqtt_trans_.total_len);
					}
					delete[] tmp;
					delete[] pread;
					});
				update_process.detach();
			}
		}
		LOGFMTD("%s", fileName.toStdString().c_str());
	}
	else if (_action->text() == "参数设置")
	{
		set_win.setVisible(false);
		set_win.setVisible(true);
	}
	else if (_action->text() == "故障屏蔽")
	{
		mask_win.setVisible(false);
		mask_win.setVisible(true);
	}
	else if (_action->text() == "恢复出厂设置")
	{
		if(action_restore_)
			GET_MQTT_HANDLE["net"]->Publish("test/ctrl/restore_factory", "restore", 7);
		else
		{
			QMessageBox::warning(this, "警告", "请检查网络或设备程序");
			return;
		}
	}
}
void desk::slot_AddWidget(QString _key, QString _value)
{
	set_arg_widget* t = new set_arg_widget;
	//根据key区分窗口
	auto result = _key.split(":");
	if (result.size() == 2)
	{
		if (result[0] == "soft_limit")
		{
			t->lab = new QLabel(set_ui.tab_limit);
			t->edit = new QLineEdit(set_ui.tab_limit);
			t->edit->setValidator(validator_);
			t->set = new QPushButton(set_ui.tab_limit);
			t->edit->setText(_value.toStdString().c_str());
			t->set->setText("设置");
			t->lab->setText(result[1]);
			set1_lay_->addWidget(t->lab, set1_lay_->count() / 6, set1_lay_->count() % 6);
			set1_lay_->addWidget(t->edit, set1_lay_->count() / 6, set1_lay_->count() % 6);
			set1_lay_->addWidget(t->set, set1_lay_->count() / 6, set1_lay_->count() % 6);
		}
		else if (result[0] == "soft_set") 
		{
			t->lab = new QLabel(set_ui.tab_arg);
			t->edit = new QLineEdit(set_ui.tab_arg);
			t->edit->setValidator(validator_);
			t->set = new QPushButton(set_ui.tab_arg);
			t->edit->setText(_value.toStdString().c_str());
			t->set->setText("设置");
			t->lab->setText(result[1]);
			set2_lay_->addWidget(t->lab, set2_lay_->count() / 6, set2_lay_->count() % 6);
			set2_lay_->addWidget(t->edit, set2_lay_->count() / 6, set2_lay_->count() % 6);
			set2_lay_->addWidget(t->set, set2_lay_->count() / 6, set2_lay_->count() % 6);
		}
		else if (result[0] == "hardware")
		{
			t->lab = new QLabel(set_ui.tab_hard);
			t->edit = new QLineEdit(set_ui.tab_hard);
			t->set = new QPushButton(set_ui.tab_hard);
			t->edit->setText(_value.toStdString().c_str());
			t->set->setText("设置");
			t->lab->setText(result[1]);
			set3_lay_->addWidget(t->lab, set3_lay_->count() / 9, set3_lay_->count() % 9);
			set3_lay_->addWidget(t->edit, set3_lay_->count() / 9, set3_lay_->count() % 9);
			set3_lay_->addWidget(t->set, set3_lay_->count() / 9, set3_lay_->count() % 9);
		}

	}
	connect(t->set, &QPushButton::clicked, [=]() {
		auto val = t->edit->text().toStdString();
		if (val == "")
		{
			QMessageBox::warning(NULL,"警告", _key+"设置值为空!!");
			return;
		}
		//test/+/param/+
		GET_MQTT_HANDLE["net"]->Publish(("test/ctrl/param/" + _key.toStdString()).c_str(), val.c_str(), val.length());
		//更新本地参数
		GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);
	});
}
//删除全部控件
void desk::slot_DelWidget()
{
	QLayoutItem* item = NULL;
	while (NULL != (item = set1_lay_->takeAt(0))) {
		item->widget()->close();//关闭但不释放
		item->widget()->deleteLater();
		item = NULL;
	}
	while (NULL != (item = set2_lay_->takeAt(0))) {
		item->widget()->close();//关闭但不释放
		item->widget()->deleteLater();
		item = NULL;
	}
	while (NULL != (item = set3_lay_->takeAt(0))) {
		item->widget()->close();//关闭但不释放
		item->widget()->deleteLater();
		item = NULL;
	}
}
void desk::slot_OnButton()
{
	LOGFMTD("%s",((QPushButton*)sender())->objectName().toStdString().c_str());
	std::string name = ((QPushButton*)sender())->objectName().toStdString();
	if (name == "btn_light_on")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_LIGHTA);
		cmd.set_lighta(true);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms",data.c_str(),data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms",cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_light_off")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_LIGHTA);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_shake_on")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_SHAKEA_MOTOR);
		cmd.set_shakea_motor(true);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	
		cmd.set_type(typeRunBms::RUN_BMS_SHAKEB_MOTOR);
		cmd.set_shakeb_motor(true);
		cmd.set_pack(1);
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());

	}
	else if (name == "btn_shake_off")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_SHAKEA_MOTOR);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	
		cmd.set_type(typeRunBms::RUN_BMS_SHAKEB_MOTOR);
		cmd.set_pack(1);
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());

	}
	else if (name == "btn_run_on")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_RUN_MOTOR);
		cmd.set_run_motor(true);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_run_off")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_RUN_MOTOR);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_height_on")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_HEIGHT_MOTOR);
		cmd.set_height_motor(true);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_height_off")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_HEIGHT_MOTOR);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
	//	GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_line_on")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_LINE_MOTOR);
		cmd.set_line_motor(true);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
	//	GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_line_off")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_LINE_MOTOR);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_rop_on")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_ROP_MOTOR);
		cmd.set_rop_motor(true);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_rop_off")
	{
		pb_run_bms cmd;
		cmd.set_type(typeRunBms::RUN_BMS_ROP_MOTOR);
		cmd.set_pack(1);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_bms", data.c_str(), data.length());
		//GET_MQTT_HANDLE["net"]->Publish("test/debug/pb_run_bms", cmd.DebugString().c_str(), cmd.DebugString().length());
	}
	else if (name == "btn_request")
	{
		//AuvTool::GetIdentifyName() + "/request/pb_run_setting
		GET_MQTT_HANDLE["net"]->Publish("test/request/pb_run_setting", "request", 7);
	}
	else if (name == "btn_h_zero")
	{
		if (ui.tabWidget->currentIndex() != 0)
		{
			QMessageBox::warning(this, "警告", "半自动或者全自动模式下禁止手动清零");
			return;
		}
		//"test/ctrl/encoder/encoder_pos"
		if (!ui.ck_root->isChecked())
		{
			QMessageBox::warning(this, "警告", "必须在管理员模式下使用");
			return;
		}
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/encoder/encoder_pos", "0", 1);
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("run");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_ZERO);
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
	}
	else if (name == "btn_v_zero")
	{
		if (ui.tabWidget->currentIndex() != 0)
		{
			QMessageBox::warning(this, "警告", "半自动或者全自动模式下禁止手动清零");
			return;
		}
		if (!ui.ck_root->isChecked())
		{
			QMessageBox::warning(this, "警告", "必须在管理员模式下使用");
			return;
		}
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("height");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_ZERO);
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());

	}
	else if (name == "btn_stop_line")
	{
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("rop");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/line", data.c_str(), data.length());
	}
	else if (name == "btn_stop_rop")
	{
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("rop");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/rop", data.c_str(), data.length());
	}
	else if (name == "btn_stop_sync")
	{
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("rop");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/rop", data.c_str(), data.length());
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/line", data.c_str(), data.length());
	}
	else if (name == "btn_stop" || name == "btn_stop_2")
	{
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("height");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_STOP);
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());

		cmd_run.set_name("run");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());

		ui.btn_up->setChecked(false);
		ui.btn_down->setChecked(false);
		ui.btn_left->setChecked(false);
		ui.btn_right->setChecked(false);
	}
	else if (name == "btn_line_sure")
	{
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("line");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd_run.set_speed_percent(stoi(ui.edit_line_motor->text().toStdString()));
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/line", data.c_str(), data.length());
	}
	else if (name == "btn_rop_sure")
	{
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("rop");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd_run.set_speed_percent(stoi(ui.edit_rop_motor->text().toStdString()));
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/rop", data.c_str(), data.length());
	}
	else if (name == "btn_set_hardware")
	{
		bool ok;
		QString text = QInputDialog::getText(this, "提示", "请输入超级密码", QLineEdit::Password, 0, &ok);
		if (ok && !text.isEmpty())
		{
			if (text == "6666")
			{
				set_ui.tabWidget->setTabEnabled(2,true);
			}
			else
			{
				QMessageBox::warning(nullptr, "警告", "密码错误");
			}

		}
		else
		{
			QMessageBox::warning(nullptr, "警告", "密码错误");
		}
	}
	else if (name == "btn_sync_sure")
	{
		std::string data;
		pb_run_ctrl cmd_run;
		cmd_run.set_name("rop_line");
		cmd_run.set_method(RUN_CTRL_METHOD::RUN_CTRL_SPEED);
		cmd_run.set_speed_percent(stoi(ui.edit_sync->text().toStdString()));
		cmd_run.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/rop", data.c_str(), data.length());
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/line", data.c_str(), data.length());
	}
	//自动模式
	else if (name == "btn_shake_time")
	{
		if (ui.btn_shake_time->text() == "开始")
		{
			ui.btn_shake_time->setText("停止");
			emit ui.btn_shake_on->clicked();
			timer_shake_flag_ = true;
			shake_time_ = std::stoi(ui.edit_shake_time->text().toStdString());
			if (timer_con_flag_) return;
			timer_con_flag_ = true;
			connect(&timer_shake_, &QTimer::timeout, [&]() {
				if (shake_time_ <= 0)
				{
					shake_time_ = 0;
					if (timer_shake_flag_)
					{
						emit ui.btn_shake_off->clicked();
						timer_shake_flag_ = false;
						ui.btn_shake_time->setText("开始");
					}
				}
				ui.lab_shake_rest->setText("剩余震动时间:" + QString::number(shake_time_--));
				});
			timer_shake_.start(1000);
		}
		else
		{
			timer_shake_flag_ = false;
			shake_time_ = 0;
			ui.btn_shake_time->setText("开始");
		}
	}
	else if (name == "btn_mode2_shake")//设置提升速度、距离
	{
		pb_run_ctrl cmd;
		cmd.set_name("height");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_POSITION);
		float pos = stof(ui.edit_height_pos->text().toStdString());
		float max_pos = 10.0;
		if (advance_set_.find("soft_limit:下降最大距离(m)") != advance_set_.end())
			max_pos = std::stoi(advance_set_["soft_limit:下降最大距离(m)"]);
		if (pos < 0 || pos > max_pos)
		{
			QMessageBox::warning(this, "警告", "提升仅允许设置0-"+QString::number(max_pos)+"m");
			return;
		}
		int16_t speed = stoi(ui.edit_height_speed->text().toStdString());
		cmd.set_speed_percent(speed);
		cmd.set_position(pos);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/height", data.c_str(), data.length());

		if (ui.ck_shake_mode2->isChecked())
			emit ui.btn_shake_on->clicked();
	}
	else if (name == "btn_mode3_shake")//设置行走电机速度、距离
	{
		pb_run_ctrl cmd;
		cmd.set_name("run");
		cmd.set_method(RUN_CTRL_METHOD::RUN_CTRL_POSITION);
		float pos = stof(ui.edit_run_pos->text().toStdString());
		int16_t speed = stoi(ui.edit_run_speed->text().toStdString());
		cmd.set_speed_percent(speed);
		cmd.set_position(pos);
		std::string data;
		cmd.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_ctrl/run", data.c_str(), data.length());
		if (ui.ck_shake_mode2->isChecked())
			emit ui.btn_shake_on->clicked();

	}
	//测试模式
	else if (name == "btn_test_start")
	{
		pb_run_test_item item;
		MakeMission(item);
		item.set_type(typeTestType::TEST_START);
		if (ui.input_times->text() == "") ui.input_times->setText("1");
		item.set_cycle_times(stoi(ui.input_times->text().toStdString()));
		LOGFMTD("%s",item.DebugString().c_str());
		std::string data;
		item.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_test_item", data.c_str(), data.length());
	}
	else if (name == "btn_test_stop")
	{
		pb_run_test_item item;
		item.set_type(typeTestType::TEST_STOP);
		std::string data;
		item.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_test_item", data.c_str(), data.length());
	}
	else if (name == "btn_test_suspend")
	{
		pb_run_test_item item;
		item.set_type(typeTestType::TEST_SUSPEND);
		std::string data;
		item.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_test_item", data.c_str(), data.length());
	}
	else if (name == "btn_test_resume")
	{
		pb_run_test_item item;
		item.set_type(typeTestType::TEST_RESUME);
		std::string data;
		item.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_test_item", data.c_str(), data.length());
	}
	else if(name == "btn_test_import")	
	{
		QString file_name = QFileDialog::getOpenFileName(this, "导入文件", ".", "*.mis");
		if (!file_name.isNull())
		{
			QFile f(file_name);
			if (f.open(QIODevice::ReadOnly))
			{
				auto s = f.readAll().toStdString();
				msgType::pb_run_test_item item;
				if (google::protobuf::TextFormat::ParseFromString(s, &item))
				{
					ui.list_test->clear();
					for (int i = 0; i < item.unit_size(); i++)
					{
						std::string line = "类型:";
						if (item.unit(i).type() == typeTestType::TEST_DELAY)
						{
							line += "延时动作-时间:";
							line += std::to_string(item.unit(i).delay_sec());
							line += "-";
							if (item.unit(i).shake_enable())
							{
								line += "震动:开";
							}
							else
							{
								line += "震动:关";
							}
							ui.list_test->addItem(line.c_str());
						}
						else if (item.unit(i).type() == typeTestType::TEST_HEIGHT)
						{
							line += "提升动作-速度:";
							line += std::to_string(item.unit(i).speed());
							line += "-距离:";
							line += std::to_string(item.unit(i).position());
							line += "-";
							if (item.unit(i).shake_enable())
							{
								line += "震动:开";
							}
							else
							{
								line += "震动:关";
							}
							ui.list_test->addItem(line.c_str());
						}
						else if (item.unit(i).type() == typeTestType::TEST_RUN)
						{
							line += "行走动作-速度:";
							line += std::to_string(item.unit(i).speed());
							line += "-距离:";
							line += std::to_string(item.unit(i).position());
							line += "-";
							if (item.unit(i).shake_enable())
							{
								line += "震动:开";
							}
							else
							{
								line += "震动:关";
							}
							ui.list_test->addItem(line.c_str());
						}
					}
				}
			}
		}
	}
	else if (name == "btn_test_export")
	{
		QString file_name = QFileDialog::getSaveFileName(this,"保存文件",".","*.mis");
		if (!file_name.isNull())
		{
			msgType::pb_run_test_item test_item;
			MakeMission(test_item);
			LOGFMTD("%s",test_item.DebugString().c_str());
			QFile f(file_name);
			if (f.open(QIODevice::ReadWrite))
			{
				f.write(test_item.DebugString().c_str());
				f.close();
			}
		}
	}

	//全自动模式
	else if (name == "btn_start_auto")
	{
		pb_run_auto auto_set;
		auto_set.set_num_a(std::stoi(ui.input_a->text().toStdString()));
		auto_set.set_run_b(std::stof(ui.input_b->text().toStdString()));
		auto_set.set_height_c(std::stof(ui.input_c->text().toStdString()));
		auto_set.set_time_d(std::stoi(ui.input_d->text().toStdString()));
		auto_set.set_force_e(std::stof(ui.input_e->text().toStdString()));
		auto_set.set_up_height_f(std::stof(ui.input_f->text().toStdString()));
		auto_set.set_cmd(1);
		std::string data;
		auto_set.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_auto", data.c_str(),data.length());
	}
	else if (name == "btn_stop_auto")
	{
		pb_run_auto auto_set;
		auto_set.set_cmd(3);
		std::string data;
		auto_set.SerializeToString(&data);
		GET_MQTT_HANDLE["net"]->Publish("test/ctrl/pb_run_auto", data.c_str(), data.length());
	}
	else if (name == "btn_suspend_auto")
	{
	}
	else if (name == "btn_resume_auto")
	{
	}
}